/****************************************************************************
CX Postfix Generator - Machine Problem 2 - CS32
Reconstructs a Binary Tree from its Preorder and Inorder traversals

Vincent Paul F. Fiestada - 201369155 - vffiestada@upd.edu.ph
*****************************************************************************/

#include "cardinal.h" // Note: 'cardinal.h' has the non-standard preprocessor directive #pragma once
#include "binarytree.h"

#define STRINGMAX 100
#define INPUTFILENAME "tree.txt"

// Error code constants
#define ERR_INPUTFILE_CANNOTOPEN 100
#define ERR_INPUTFILE_CORRUPT_LINES 102
#define ERR_INPUTSTR_LEN_MISMATCH 103
#define ERR_INPUTSTR_SET_MISMATCH 104

// Function declarations; see below for definitions
char * mfgets(char * saveto, float length, FILE * source);
char * smallcaps (char * fc);

int main()
{
	printf("\n=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n");
	printf("       CX Tree Traversal Parser || CS 32 Machine Problem 2\n");
	printf("Vincent Paul F. Fiestada | 201369155 | vffiestada@upd.edu.ph\n");
	printf("=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+\n");

	// Create and initialize variables
	FILE * inputFile;
	char tempstring[STRINGMAX];
	char * tempchar;
	char inputs[3][STRINGMAX];
	int i = 0; // iterator; reusable
	BinaryTree * mahtree;

	// Read input
	inputFile = fopen(INPUTFILENAME, "r");	// open input file
	if (inputFile==NULL) // If inputFile is null, then the stream couldn't be opened; report error
	{
		fprintf(stderr,"\nFATAL ERROR!\nFailed to open '%s'. ",INPUTFILENAME);
		exit(ERR_INPUTFILE_CANNOTOPEN); // exit with appropriate error code
	}
	for (i = 0; i < 2; i++)
	{
		tempchar = mfgets(tempstring, STRINGMAX, inputFile); // Read the first line
		if (tempchar == NULL) // If first line is empty, report an error
		{
			fprintf(stderr,"\nFATAL ERROR!\nSome data is missing from the file '%s'. Make sure it is properly formatted and try again.\n",INPUTFILENAME);
			exit(ERR_INPUTFILE_CORRUPT_LINES);
		}
		// If no errors, copy into input
		strcpy(&(inputs[i][0]), tempchar);
	}
	fclose(inputFile); // close input file

	// Check input for errors
	// 1) string lengths must be equal
	if (strlen(inputs[0]) != strlen(inputs[1]))
	{
		fprintf(stderr,"\nInvalid Input!\nThe string lengths of your inputs do not match.\n");
		exit(ERR_INPUTSTR_LEN_MISMATCH);
	}
	// 2) Everything in preorder must be inorder and vice versa
	for(i = 0; i < strlen(inputs[0]); i++)
	{
		if (strchr(inputs[0], inputs[1][i]) == NULL || strchr(inputs[1], inputs[0][i]) == NULL)
		{
			fprintf(stderr,"\nInvalid Input!\nThe traversals do not match.\n");
			exit(ERR_INPUTSTR_SET_MISMATCH);
		}
	}

	printf("\nINPUT 1 (Preorder): %s", inputs[0]);
	printf("\nINPUT 1 (Inorder): %s", inputs[1]);

	// Create binary tree
	mahtree = CreateBinaryTree();

		printf("\n\nReconstructed Tree: ");
	BinaryTree * tempt = PreInordertoBinTree(mahtree, inputs[0], inputs[1]);

	if (tempt == NULL) // Check for errors
	{
		printf("\n\nERROR! Invalid Input: Could not reconstruct tree. DEBUG NEEDED::PreInordertoBinTree(...)\n");
		// Clean up;
		// Annihilate binary tree
		AnnihilateBinaryTree(mahtree);
		exit(ERR_INPUTSTR_SET_MISMATCH);
	}
	else
	{
		PrintBinaryTree(mahtree->Root, 0);
	}

	printf("\n\nTraversals: ");
	printf("\n----------------------------------------------------");
	char traversal[STRINGMAX] = "";
    tempchar = LinkInversionTraversal(mahtree, traversal, 1);
    printf("\nPREORDER           : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LinkInversionTraversal(mahtree, traversal, 2);
    printf("\nINORDER            : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LinkInversionTraversal(mahtree, traversal, 3);
    printf("\nPOSTORDER          : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LevelOrderTraversal(mahtree->Root, traversal);
    printf("\nLEVEL ORDER        : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LinkInversionTraversal(mahtree, traversal, 5);
    printf("\nCONVERSE PREORDER  : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LinkInversionTraversal(mahtree, traversal, 6);
    printf("\nCONVERSE INORDER   : %s", traversal);
    tempchar[0] = '\0'; // reset string
    tempchar = LinkInversionTraversal(mahtree, traversal, 7);
    printf("\nCONVERSE POSTORDER : %s", traversal);
    printf("\n\n*All traversals, except for Level Order, are generated by Link Inversion.");

	// Clean up;
	// Annihilate binary tree
	AnnihilateBinaryTree(mahtree);
	printf("\n");
	return 0;
}

//<summary>
// mfgets - Modified fgets - reads string from a FILE stream, cleans up the string
//        and returns pointer to the stored string
//</summary>
char * mfgets(char * saveto, float length, FILE * source){
	char * trim;
	// mfgets(...) returns pointer to saveto
	//  after reading string into it.
	saveto = fgets(saveto, length, source);
	// Check for Error in reading string from stream
	if(saveto==NULL){
		return NULL;
	}
	// Trim the string for whitespaces
	// First, look for leading newlines, tabs, and spaces
	trim = saveto;
	while(*trim != '\0' && (*trim == '\n' || *trim == '\t' || *trim == ' '))
	{
		saveto++; // Move string pointer to the next one (discard previous whitespace)
		trim++;
	}
	// Second, look for trailing whitespace
	trim = saveto + strlen(saveto) - 1;; // Start with the last char (before the terminating null)
	while(*trim == '\n' || *trim == '\t' || *trim == ' ')
	{
		*trim = '\0'; // Replace with terminating null
		trim--;
	}
	saveto = smallcaps(saveto);
	return saveto;
}

//<summary>
// smallcaps - converts a string into all small caps
//</summary>
char * smallcaps (char * fc){
	char * curr_letter = fc;
	while(*curr_letter!='\0'){
		if(*curr_letter>=65&&*curr_letter<=90){
			*curr_letter += 32;		//Make small-caps
		}
		curr_letter++;
	}
	return fc;
}